Skip to content

feat(pet): Mimi's own notice tools — Notices, Triggers, ManageTrigger, NotificationSettings and snooze - #356

Merged
cjhyy merged 7 commits into
mainfrom
claude/pet/mimi-own-tools-20261112
Nov 12, 2026
Merged

cjhyy merged 7 commits into
mainfrom
claude/pet/mimi-own-tools-20261112

Conversation

@cjhyy

@cjhyy cjhyy commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Gives Mimi her own tools for the notice system, so the owner can manage it by talking to her.

Tools (Mimi only; never exposed to worker sessions or external runtimes)

  • Notices (read): notices sent to the owner, filterable by kind/session/time. Each one carries kind, title, text (≤600 chars), local time, where it went, delivery status, session/task, and brief record refs. It never returns conversation, sender or platform ids, reply codes, item labels or media paths. Results are framed as untrusted data.
  • Triggers (read): the same list as Mimi settings › 规则与跟进.
  • ManageTrigger: pause / resume / cancel any rule; enable / disable / set_time / set_active_hours for briefs and heartbeat (through settings). Accepts changes: [...] (≤5) in one call. It reuses the settings page's update logic, and the host appends the real outcome. Creating follow-ups stays with ManageFollowUp.
  • NotificationSettings: read, and update only the fields given (quiet hours, caps, digest slots, briefs, heartbeat, …). Also a temporary snooze (≤24 h, snoozeUntil in settings): everything except P0 decisions and immediate notices is held and digested when the snooze ends. It survives restarts and expires on its own; the settings page shows "静音到 HH:MM" with a cancel button.
  • Auto-context: when the owner messages Mimi, her turn gets the ≤3 briefs/heartbeat messages she sent that conversation in the last 12 h (desktop or the owner's private chat only).

Authority

  • The notice tools exist only in owner turns: desktop, or an allowlisted IM private chat. The dispatcher hides them in group, non-owner and unverifiable turns, and the host also refuses reads and changes outside an owner turn.
  • Origin is derived by the host, never taken from model args.

Not verified

Not tried in the real app.

🤖 Generated with Claude Code

cjhyy and others added 7 commits November 12, 2026 12:23
`settings.pet.notifications.snoozeUntil` (epoch ms, at most a day ahead)
holds every non-decision notice for the digest until it ends: P1/P2
results, briefs and heartbeat (resent whole), and owner-timed follow-ups
(the owner's newer "not now" wins). P0 decisions and immediate answers
still go out. A past or implausible (>24 h away) end no longer applies,
so it expires by itself and survives restarts.

A settings change re-runs the digest flush, so ending a snooze early
sends what it held. The 通知与主动 card shows "静音到 HH:MM" with a
cancel that writes only `snoozeUntil: null` through the existing settings
path; `pet:notices:get-state` carries it in the settings view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four Mimi-only tools over the notice system (design §4.7):

- Notices (read): what was sent to the owner, filtered by kinds,
  session, since/until and limit (10, max 30), framed as untrusted data.
- Triggers (read): the settings page's rule list.
- ManageTrigger: pause / resume / cancel a listed trigger, and for Mimi's
  system triggers enable / disable, set_time (brief) and
  set_active_hours (heartbeat), with optional expected_version.
- NotificationSettings: read, or a touched-only update of the pacing
  settings plus a temporary snooze ({minutes} | {until}, <= 24 h; null
  cancels).

Reads are synchronous host loopbacks; changes are deferred host actions
(noticeTriggerMutation, notificationSettingsMutation) validated on both
sides, so the host decides authority from the turn after it ends. The
tools are visible only to the pet profile with those action kinds and,
lacking an external declaration, stay out of PET_MANAGER_TOOL_CATALOG.
Mimi's prompt gains a short section on when to use each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Read loopbacks (pet.notices.query / pet.triggers.query /
  pet.notifications.read) registered on the worker bridge; they answer
  Mimi's own Session only. Notices come from the ledger newest first
  (kind / session / time filters, text cut to 600, owner-local ISO times,
  where it went and its delivery status, Session, task id and a brief's
  record refs); no conversation, sender or platform id, reply code or
  media path is returned. Triggers is the settings rule list, plus the
  system triggers' enable / disable / set_time / set_active_hours.
- Deferred executors noticeTriggerMutation and
  notificationSettingsMutation. Authority comes from the turn: the
  desktop owner, or an allowlisted owner conversation that is a private
  chat; group chats, other senders and turns without routing facts are
  refused and nothing is written. Rule changes reuse the rule list's
  updater (version conflicts, not_allowed, system rules via settings);
  settings writes are touched-only, re-checked against the settings
  schema, and go through the same pet.notifications write as the page.
  Snooze is {minutes} | {until} within 24 h, or null to end it.
- The host's own outcome text is appended to Mimi's reply.
- Brief notices keep their record refs, task closures their task id.
- Desktop Mimi turns offer the two change kinds as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the owner messages Mimi, her runtime context now carries
`recentProactive`: the briefs and heartbeat messages she sent that
conversation in the last 12 hours (at most three, text cut to 600,
eight short record refs each), framed as "you sent these earlier".
An IM turn sees only what reached its channel, and only as the owner's
private chat; the desktop sees everything sent to the owner. Follow-up
wakes and unaddressed sources get none.

The pendingNotices block moved with it into pet-notice-world.ts, so the
dispatcher shrinks (2490 -> 2479 lines). CI runs the new desktop suites
in the bounded notice process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds §4.7 (the four tools, transport, authority, reuse of the rule-list
updater and settings write, recentProactive), the snoozeUntil setting
and its routing in §11, and in §15 drops the "Mimi does not know what
the brief said" limitation in favour of the new trade-offs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups for Mimi's notice tools:

- C1: the dispatcher runs ownerTurnRefusal on the turn's own routing
  facts before building its host-action kinds; group chats, non-owner
  conversations, unverifiable sources and follow-up wakes get neither
  notice kind, so all four tools are hidden. As defence in depth a
  per-Session turn gate (set when the run starts, cleared when it ends)
  makes the read loopbacks refuse any turn that is not the owner's.
- I2: ManageTrigger takes changes=[...] (at most 5) in one call; the
  host applies them in order against fresh versions and writes one
  outcome line per change (the action fails only when none applied).
  The single-change form is unchanged; prompt and description show
  "停掉晨报和心跳" as one call.
- M3: recentProactive is framed as untrusted data, never instructions.
- M4: Notices / recentProactive text drop an item's ①② label and the
  host's reply-hint line by exact match, and a decision prompt is given
  as its question and options; reply codes never appear (tested).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- M6: a snooze's end alone sends the digest through the armed timer,
  and a restart during the snooze re-arms it for the end.
- M5: the spec says an allowlisted non-owner private chat counts as the
  owner (same as IM decision codes), and records C1 / I2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cjhyy
cjhyy merged commit 8bd1eec into main Nov 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant